#ifndef VEC2D_H_
#define VEC2D_H_

#include <cmath>

/* Wektor dwuwymiarowy. */
template <typename T>
struct Vec2d {
	T x;
	T y;

	Vec2d(): x( static_cast< T >( 0.0 )), y( static_cast<T>( 0.0 )) {};
	Vec2d( T X, T Y ): x( X ), y( Y ) {};

	/* Tworzy wektor o podanej dlugosci i nachylony pod zadanym katem (w radianach). */
	static Vec2d<T> instantiateRotatedVector( T magnitude, float angle ) {
		return Vec2d<T>(
			static_cast<T>( magnitude * cos( angle ) ),
			static_cast<T>( magnitude * sin( angle ) )
		);
	};

	Vec2d<T>& operator=( const Vec2d<T>& v ) {
		if( this != &v ) {
			x = v.x;
			y = v.y;
		} return *this;
	}

	bool operator!=( const Vec2d<T>& v ) const {
		return ( (x != v.x) || (y != v.y) );
	};

	bool operator==( const Vec2d<T>& v ) const {
		return ( (x == v.x) && (y == v.y) );
	};

	Vec2d<T> operator+( const Vec2d<T>& v ) const {
		return Vec2d<T>( x+v.x, y+v.y );
	};

	Vec2d<T> operator+( T v ) const {
		return Vec2d<T>( x+v, y+v );
	};

	Vec2d<T> operator-( const Vec2d<T>& v ) const {
		return Vec2d<T>( x-v.x, y-v.y );
	};

	Vec2d<T> operator-( T v ) const {
		return Vec2d<T>( x-v, y-v );
	};

	Vec2d<T> operator*( const Vec2d<T>& v ) const {
		return Vec2d<T>( x*v.x, y*v.y );
	};

	Vec2d<T> operator*( T v ) const {
		return Vec2d<T>( x*v, y*v );
	};

	Vec2d<T> operator/( const Vec2d<T>& v ) const {
		return Vec2d<T>( x/v.x, y/v.y );
	};

	Vec2d<T> operator/( T v ) const {
		return Vec2d<T>( x/v, y/v );
	};

	Vec2d<T>& operator+=( const Vec2d<T>& v ) {
		x+=v.x;
		y+=v.y;
		return *this;
	};

	Vec2d<T>& operator-=( const Vec2d<T>& v ) {
		x-=v.x;
		y-=v.y;
		return *this;
	};

	Vec2d<T>& operator*=( const Vec2d<T>& v ) {
		x*=v.x;
		y*=v.y;
		return *this;
	};

	Vec2d<T>& operator*=( T v ) {
		x*=v;
		y*=v;
		return *this;
	};

	Vec2d<T>& operator/=( const Vec2d<T>& v ) {
		x/=v.x;
		y/=v.y;
		return *this;
	};

	bool operator>=( const T n ) {
		return ( (x >= n) && (y >= n) );
	};

	bool operator<=( const T n ) {
		return ( (x <= n) && (y <= n) );
	};

	bool operator>( const T n ) {
		return ( (x > n) && (y > n) );
	};

	bool operator<( const T n ) {
		return ( (x < n) && (y < n) );
	};

	double magnitude() const {
		return sqrt( x*x + y*y );
	};

	Vec2d<T> normalize() const {
		double mag = magnitude();
		return Vec2d<T>( static_cast<T>( x / mag ), static_cast<T>( y / mag ) );
	};
	
	/* Podaje kat nachylenia wektora do osi OX w radianach (w zakresie 0..2*PI radianow). */
	float angle() const {
		float angle = acos( x / magnitude() );
		if( x > 0 ) {
			//return angle;
			if( y >= 0 ) {
				return angle;
			} else {
				return 6.28 - angle;
				//return 3.14f + angle;
				//return 0.75f*6.28f + angle;
			}
		} else if( x < 0 ) {
			if( y >= 0 ) {
				return angle;
				//return 0.5f*3.14f - angle;
			} else {
				return 6.28 - angle;
				//return 0.75f*6.28f - angle;
			}
		} else {
			if( y >= 0 ) return 0.5f * 3.14f;
				else return 0.75f * 6.28f;
		}
	}

	/* Oblicza kat wektora vec1 w stosunku do wektora vec2. */
	static double vectors_angle(const Vec2d<T>& vec1, const Vec2d<T>& vec2){
		return vec1.angle() - vec2.angle();
		/*
        double a =(vec1.x*vec2.x + vec1.y*vec2.y);        
        double b = vec1.magnitude()*vec2.magnitude();
        return acos(a/b);
        */
    };

	//static const Vec2d<T> ZERO;

};

/* Dwuwymiarowy wektor liczb zmiennoprzecinkowych. */
typedef Vec2d< float > Vec2f;

/* Dwuwymiarowy wektor liczb calkowitych. */
typedef Vec2d< int > Vec2i;

#endif /* VEC2D_H_ */
